Alright, I figured out a way to identify the server by contacting it via https and then checking its certificate. That should be pretty reliable.
Below the code I use, though I ran into one complication: The mount URL I get for my QNAP NAS is: "QNAS._smb._tcp.local", but that is not a valid host name I can use in a NSURLRequest!
I need to transform that into the actual host name, which is "QNAS.local". Since the former is a Bonjour related name, and when I browse the Bonjour registry with BonJeff, I can find the mapping, this seems to be an overly complicated method. I wonder what the proper way is to get the basic host name from such a service name. I've googled for a while but could not find anything about it. For now, I simply remove all components from the host name that start with an underscore, but I'm not sure if that's a safe method.
#import <NetFS/NetFS.h>
#import <Security/Security.h>
#import "AppDelegate.h"
@interface AppDelegate () <NSURLSessionDelegate>
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
CFURLRef furl = CFURLCreateWithFileSystemPath(NULL, CFSTR("/Volumes/TheNAS"), kCFURLPOSIXPathStyle, true);
NSURL *url = CFBridgingRelease(NetFSCopyURLForRemountingVolume (furl));
NSArray *parts = [[url.host componentsSeparatedByString:@"."] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString* _Nullable part, id _Nullable bindings) {
return ![part hasPrefix:@"_"];
}]];
NSString *addr = [parts componentsJoinedByString:@"."];
NSLog(@"host: %@ -> %@", url.host, addr);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@", addr]]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"Done.");
[NSApp terminate:self];
}] resume];
}
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trustRef, 0);
CFStringRef name = nil;
SecCertificateCopyCommonName(certRef, &name);
NSLog(@"name: %@", name);
// reject the challenge because we have all we wanted
completionHandler (NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
@end